package com.whfc.fvs.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.AssertUtil;
import com.whfc.common.util.MathUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.fuum.service.SysDeptService;
import com.whfc.fvs.dao.FvsDeviceMapper;
import com.whfc.fvs.dao.FvsStreamMapper;
import com.whfc.fvs.dto.*;
import com.whfc.fvs.entity.FvsDevice;
import com.whfc.fvs.enums.FvsDevicePtzOption;
import com.whfc.fvs.enums.FvsDeviceStatus;
import com.whfc.fvs.enums.FvsDeviceType;
import com.whfc.fvs.enums.VsPlatform;
import com.whfc.fvs.param.FvsDeviceAddParam;
import com.whfc.fvs.param.FvsDeviceEditParam;
import com.whfc.fvs.param.FvsDeviceListParam;
import com.whfc.fvs.service.FvsDeviceService;
import com.whfc.fvs.service.factroy.FvsPlatformServiceFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 视频监控
 *
 * @author guodong_sun
 * @date 2019年10月24日
 */
@DubboService(interfaceClass = FvsDeviceService.class, version = "1.0.0", timeout = 30 * 1000)
public class FvsDeviceServiceImpl implements FvsDeviceService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService sysDeptService;

    @Autowired
    private FvsPlatformServiceFactory platformServiceFactory;

    @Autowired
    private FvsDeviceMapper fvsDeviceMapper;

    @Autowired
    private FvsStreamMapper fvsStreamMapper;


    @Override
    public PageData<FvsDeviceDTO> deviceList(FvsDeviceListParam fvsDeviceListParam) throws BizException {
        logger.info("获取监控设备列表, params:{}", fvsDeviceListParam);
        String keyword = fvsDeviceListParam.getKeyword();
        Integer groupId = fvsDeviceListParam.getGroupId();
        Integer deviceType = fvsDeviceListParam.getDeviceType();
        Integer pageNum = fvsDeviceListParam.getPageNum();
        Integer pageSize = fvsDeviceListParam.getPageSize();
        Integer deptId = fvsDeviceListParam.getDeptId();
        Integer deviceStatus = fvsDeviceListParam.getDeviceStatus();
        String platform = fvsDeviceListParam.getPlatform();
        Integer webcamType = fvsDeviceListParam.getWebcamType();

        PageHelper.startPage(pageNum, pageSize);
        List<FvsDeviceDTO> list = fvsDeviceMapper.selectDeviceList(deptId, groupId, keyword, deviceType, deviceStatus, platform, webcamType);
        for (FvsDeviceDTO fvsDeviceDTO : list) {
            if (FvsDeviceType.DVR.getValue().equals(fvsDeviceDTO.getDeviceType())) {
                //查找通道设备
                List<FvsDeviceDTO> children = fvsDeviceMapper.selectDeviceByPid(fvsDeviceDTO.getId());
                fvsDeviceDTO.setChildren(children);
            }
        }
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public PageData<FvsDeviceDTO> list(FvsDeviceListParam fvsDeviceListParam) throws BizException {
        logger.info("获取监控列表, params:{}", fvsDeviceListParam);
        Integer deptId = fvsDeviceListParam.getDeptId();
        List<Integer> deptIds = sysDeptService.getDescendantDeptIdList(deptId);
        fvsDeviceListParam.setDeptId(null);
        fvsDeviceListParam.setDeptIds(deptIds);
        PageHelper.startPage(fvsDeviceListParam.getPageNum(), fvsDeviceListParam.getPageSize());
        List<FvsDeviceDTO> list = fvsDeviceMapper.selectFvsList(fvsDeviceListParam);
        String deptName = sysDeptService.getDeptName(deptId);
        for (FvsDeviceDTO fvsDeviceDTO : list) {
            fvsDeviceDTO.setDeptName(deptName);
        }
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public ListData<FvsDeviceDTO> listData(FvsDeviceListParam fvsDeviceListParam) {
        logger.info("获取监控设备列表(不分页), params:{}", fvsDeviceListParam);
        List<Integer> deptIds = sysDeptService.getDescendantDeptIdList(fvsDeviceListParam.getDeptId());
        fvsDeviceListParam.setDeptId(null);
        fvsDeviceListParam.setDeptIds(deptIds);
        List<FvsDeviceDTO> list = fvsDeviceMapper.selectFvsList(fvsDeviceListParam);
        return new ListData<>(list);
    }

    @Override
    public List<FvsDeviceDTO> list(Integer platform) throws BizException {
        logger.info("根据平台获取监控设备列表, platform:{}", platform);
        return fvsDeviceMapper.selectByPlatform(platform);
    }

    @Override
    public List<FvsDeviceDTO> list(List<Integer> deviceIdList) throws BizException {
        logger.info("根据设备ID列表获取监控设备列表, deviceIdList:{}", deviceIdList);
        if (deviceIdList == null || deviceIdList.isEmpty()) {
            return new ArrayList<>();
        }
        return fvsDeviceMapper.selectByDeviceIdList(deviceIdList);
    }

    @Override
    public List<FvsDeviceDTO> listByDeptIdList(List<Integer> deptIdList) throws BizException {
        logger.info("根据组织机构ID列表获取监控设备列表, deptIdList:{}", deptIdList);
        return fvsDeviceMapper.selectDeviceListByDeptIdList(deptIdList);
    }

    @Override
    public FvsDeviceDTO detail(Integer id) throws BizException {
        logger.info("获取监控设备详情, id:{}", id);
        FvsDeviceDTO appFvsDTO = fvsDeviceMapper.selectFvsDeviceDetail(id);
        if (appFvsDTO != null && VsPlatform.LIVE_URL_PLAY.getValue().toString().equals(appFvsDTO.getPlatform())) {
            String playUrl = "";
            FvsStreamDTO fvsStreamDTO = fvsStreamMapper.selectByDeviceId(appFvsDTO.getId());
            if (fvsStreamDTO != null) {
                if (StringUtils.isNotEmpty(fvsStreamDTO.getHls())) {
                    playUrl = fvsStreamDTO.getHls();
                } else if (StringUtils.isNotEmpty(fvsStreamDTO.getRtmp())) {
                    playUrl = fvsStreamDTO.getRtmp();
                } else if (StringUtils.isNotEmpty(fvsStreamDTO.getPlayUrl())) {
                    playUrl = fvsStreamDTO.getPlayUrl();
                }
            }
            appFvsDTO.setPlayUrl(playUrl);
        }
        return appFvsDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deviceAdd(FvsDeviceAddParam deviceAddParam) throws BizException {
        logger.info("添加监控设备, params:{}", deviceAddParam);
        VsPlatform platform = VsPlatform.parseValue(Integer.valueOf(deviceAddParam.getPlatform()));
        if (platform == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "平台类型错误.");
        }

        FvsDevice fvsDevice = new FvsDevice();
        //保存设备基本信息
        fvsDevice.setPlatform(platform.getValue().toString());
        fvsDevice.setName(deviceAddParam.getName());
        fvsDevice.setDeptId(deviceAddParam.getDeptId());
        fvsDevice.setModel(deviceAddParam.getModel());
        fvsDevice.setSize(deviceAddParam.getSize());
        fvsDevice.setGroupId(deviceAddParam.getGroupId());
        fvsDevice.setWebcamType(deviceAddParam.getWebcamType());
        fvsDevice.setDeviceType(deviceAddParam.getDeviceType());
        fvsDevice.setPlayMode(deviceAddParam.getPlayMode());
        fvsDevice.setStreamMode(deviceAddParam.getStreamMode());
        fvsDevice.setPtz(deviceAddParam.getPtz());
        fvsDevice.setDeviceStatus(FvsDeviceStatus.ONLINE.getValue());
        fvsDevice.setSn(deviceAddParam.getSn());
        fvsDeviceMapper.insertSelective(fvsDevice);

        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        platformServiceFactory.getFvsPlatFromService(platform).addDevice(fvsDeviceDTO, deviceAddParam);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deviceEdit(FvsDeviceEditParam deviceEditParam) throws BizException {
        logger.info("修改监控设备, params:{}", deviceEditParam);
        Integer deviceId = deviceEditParam.getId();
        FvsDevice fvsDevice = fvsDeviceMapper.selectByPrimaryKey(deviceId);
        if (fvsDevice == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备不存在.");
        }
        fvsDevice.setName(deviceEditParam.getName());
        Integer groupId = deviceEditParam.getGroupId();
        fvsDevice.setGroupId(groupId);
        fvsDevice.setSize(deviceEditParam.getSize());
        fvsDevice.setSn(deviceEditParam.getSn());
        fvsDevice.setModel(deviceEditParam.getModel());
        fvsDevice.setWebcamType(deviceEditParam.getWebcamType());
        fvsDevice.setPlayMode(deviceEditParam.getPlayMode());
        fvsDevice.setStreamMode(deviceEditParam.getStreamMode());
        fvsDevice.setPtz(deviceEditParam.getPtz());
        fvsDevice.setIdx(deviceEditParam.getIdx());
        if (FvsDeviceType.DVR.getValue().equals(fvsDevice.getDeviceType())) {
            //硬盘录像机需要修改子节点班组状态
//            fvsDeviceMapper.updateDeviceGroupIdByPid(fvsDevice.getId(), groupId);
        }
        fvsDeviceMapper.updateByPrimaryKeySelective(fvsDevice);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delDevice(Integer id) throws BizException {
        logger.info("删除监控设备, id:{}", id);
        FvsDevice fvsDevice = fvsDeviceMapper.selectByPrimaryKey(id);
        if (fvsDevice == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备不存在.");
        }
        AssertUtil.isTrue(fvsDevice.getDeviceStatus() != null && fvsDevice.getDeviceStatus() == 1, "在线设备不允许删除");
        fvsDeviceMapper.deleteLogicById(id);
        VsPlatform platform = VsPlatform.parseValue(Integer.valueOf(fvsDevice.getPlatform()));
        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        platformServiceFactory.getFvsPlatFromService(platform).deleteDevice(fvsDeviceDTO);
    }

    @Override
    public FvsStreamDTO getStreamUrl(Integer deviceId) throws BizException {
        logger.info("获取直播地址, deviceId:{}", deviceId);
        FvsDevice fvsDevice = fvsDeviceMapper.selectByPrimaryKey(deviceId);
        if (fvsDevice == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备不存在.");
        }
        if (fvsDevice.getDeviceStatus() == 0) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "设备已离线");
        }
        VsPlatform platform = VsPlatform.parseValue(Integer.valueOf(fvsDevice.getPlatform()));
        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        FvsStreamDTO fvsStreamDTO = platformServiceFactory.getFvsPlatFromService(platform).getStreamUrl(fvsDeviceDTO);
        fvsStreamDTO.setPtz(fvsDevice.getPtz());
        fvsStreamDTO.setSn(fvsDevice.getSn());
        fvsStreamDTO.setModel(fvsDevice.getModel());
        return fvsStreamDTO;
    }

    @Override
    @Async
    public void ptz(Integer deviceId, FvsDevicePtzOption devicePtzOption) throws BizException {
        logger.info("调整监控设备方位, deviceId:{}, devicePtzOption:{}", deviceId, devicePtzOption);
        FvsDevice fvsDevice = fvsDeviceMapper.selectByPrimaryKey(deviceId);
        if (fvsDevice == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备不存在.");
        }
        VsPlatform platform = VsPlatform.parseValue(Integer.valueOf(fvsDevice.getPlatform()));
        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        platformServiceFactory.getFvsPlatFromService(platform).ptz(fvsDeviceDTO, devicePtzOption);
    }

    @Override
    public ListData<FvsRecordDTO> getRecordList(Integer deviceId, Date startTime, Date endTime) throws BizException {
        logger.info("获取回放记录, deviceId:{}, startTime:{}, endTime:{}", deviceId, startTime, endTime);
        FvsDevice fvsDevice = fvsDeviceMapper.selectByPrimaryKey(deviceId);
        if (fvsDevice == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备不存在.");
        }
        VsPlatform platform = VsPlatform.parseValue(Integer.valueOf(fvsDevice.getPlatform()));
        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        return platformServiceFactory.getFvsPlatFromService(platform).getRecordList(fvsDeviceDTO, startTime, endTime);
    }

    @Override
    public List<FvsStreamDTO> listStreams(Integer deptId, Integer bizType, Integer platform) throws BizException {
        logger.info("获取直播地址列表, deptId:{}, bizType:{}, platform:{}", deptId, bizType, platform);
        return fvsStreamMapper.selectStreamDTOList(deptId, bizType, platform);
    }

    @Override
    public FvsDeviceNumDTO getFvsDeviceNum(List<Integer> deptIds) throws BizException {
        logger.info("获取监控设备列表, deptIds:{}", deptIds);
        FvsDeviceNumDTO data = new FvsDeviceNumDTO();
        Integer fvsNum = fvsDeviceMapper.countFvsDeviceNum(deptIds, null);
        Integer fvsOnlineNum = fvsDeviceMapper.countFvsDeviceNum(deptIds, FvsDeviceStatus.ONLINE.getValue());
        data.setFvsNum(fvsNum);
        data.setFvsOnlineNum(fvsOnlineNum);
        return data;
    }

    @Override
    public FvsTokenDTO getToken(Integer deptId, Integer platform) throws BizException {
        logger.info("获取监控token, deptId:{}, platform:{}", deptId, platform);
        VsPlatform vsPlatform = VsPlatform.parseValue(platform);
        if (vsPlatform == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "监控平台错误.");
        }
        return platformServiceFactory.getFvsPlatFromService(vsPlatform).getToken(deptId);
    }

    @Override
    public void batchUpdateDeviceStatus(List<Integer> deviceIdList, FvsDeviceStatus fvsDeviceStatus) throws BizException {
        logger.info("批量更新设备状态, deviceIdList:{}, fvsDeviceStatus:{}", deviceIdList, fvsDeviceStatus);
        if (deviceIdList == null || deviceIdList.isEmpty()) {
            return;
        }
        fvsDeviceMapper.batchUpdateDeviceStatus(deviceIdList, fvsDeviceStatus.getValue());
    }

    @Override
    public void updateSnapshotUrlByGbId(String gbId, String snapshotUrl) throws BizException {
        fvsDeviceMapper.updateSnapshotUrlByGbId(gbId, snapshotUrl);
    }

    @Override
    public void updateByAliDeviceId(String aliDeviceId, Integer deviceStatus, Integer streamStatus) throws BizException {
        fvsDeviceMapper.updateByAliDeviceId(aliDeviceId, deviceStatus, streamStatus);
    }

    @Override
    public void updateByAliStreamId(String aliStreamId, Integer deviceStatus, Integer streamStatus, String snapshotUrl) throws BizException {
        fvsDeviceMapper.updateByAliStreamId(aliStreamId, deviceStatus, streamStatus, snapshotUrl);
    }

    @Override
    public FvsDeviceDTO selectByGbId(String gbId) throws BizException {
        FvsDevice fvsDevice = fvsDeviceMapper.selectByGbId(gbId);
        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        if (fvsDevice == null) {
            return fvsDeviceDTO;
        }
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        return fvsDeviceDTO;
    }

    @Override
    public FvsDeviceDTO selectByAliDeviceId(String aliDeviceId) throws BizException {
        FvsDevice fvsDevice = fvsDeviceMapper.selectByAliDeviceId(aliDeviceId);
        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        if (fvsDevice == null) {
            return fvsDeviceDTO;
        }
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        return fvsDeviceDTO;
    }

    @Override
    public FvsDeviceDTO selectByAliStreamId(String aliStreamId) throws BizException {
        FvsDevice fvsDevice = fvsDeviceMapper.selectByAliStreamId(aliStreamId);
        FvsDeviceDTO fvsDeviceDTO = new FvsDeviceDTO();
        if (fvsDevice == null) {
            return fvsDeviceDTO;
        }
        BeanUtils.copyProperties(fvsDevice, fvsDeviceDTO);
        return fvsDeviceDTO;
    }

    @Override
    public AliyunStreamInfoDTO getAliStreamInfo(String appName, String stream) throws BizException {
        FvsAliyunRTMPVsServiceImpl rtmpVsService = (FvsAliyunRTMPVsServiceImpl) platformServiceFactory
                .getFvsPlatFromService(VsPlatform.ALIYUN_RTMP);
        return rtmpVsService.getStreamInfo(appName, stream);
    }

    @Override
    public List<FvsDeviceDTO> listWeighRoomDevice(FvsDeviceListParam fvsDeviceListParam) throws BizException {
        logger.info("物资模块获取监控设备列表, params:{}", fvsDeviceListParam);
        List<FvsDeviceDTO> list = new ArrayList<>();
        if (fvsDeviceListParam.getWeighRoomIds() == null || fvsDeviceListParam.getWeighRoomIds().isEmpty()) {
            return list;
        }
        list = fvsDeviceMapper.selectFvsList(fvsDeviceListParam);
        return list;
    }

    @Override
    public List<FvsDeviceDTO> listFvsDeviceSimpleInfo(Integer deptId) throws BizException {
        logger.info("获取监控设备简单信息, deptId:{}", deptId);
        List<FvsDeviceDTO> list = new ArrayList<>();
        if (deptId == null) {
            return list;
        }
        list = fvsDeviceMapper.selectSimpleInfoFvsList(deptId);
        return list;
    }

    @Override
    public List<FvsVideoDTO> getVideoList(Integer deptId) throws BizException {
        logger.info("获取视频地址列表, deptId:{}", deptId);
        List<FvsVideoDTO> videoList = new ArrayList<>();
        List<FvsStreamDTO> list = fvsStreamMapper.selectStreamByDeptId(deptId);
        for (FvsStreamDTO fvsStreamDTO : list) {
            FvsVideoDTO video = new FvsVideoDTO();
            video.setValue(fvsStreamDTO.getName());
            video.setUrl(fvsStreamDTO.getHls());
            videoList.add(video);
        }
        return videoList;
    }

    @Override
    public List<FvsStreamDTO> getVideoList1(Integer deptId) throws BizException {
        logger.info("获取视频地址列表V1, deptId:{}", deptId);
        return fvsStreamMapper.selectStreamByDeptId(deptId);
    }


    @Override
    public FvsAnalysisDTO analysis(Integer deptId) throws BizException {
        logger.info("获取视频统计, deptId:{}", deptId);
        FvsAnalysisDTO data = fvsDeviceMapper.analysis(deptId);
        if (data.getOnlineNum() == null || data.getOnlineNum() == 0) {
            data.setOnlineNum(0);
            data.setOnlineRate(0D);
            return data;
        }
        data.setOnlineRate(MathUtil.round(MathUtil.divide(data.getOnlineNum(), data.getTotalNum(), 4) * 100, 2));
        return data;
    }

    @Override
    public FvsDeviceDTO selectBySn(String sn) {
        return fvsDeviceMapper.selectBySn(sn);
    }
}